home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / stunnel-4.04 / _src / src / stunnel.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-12  |  18.6 KB  |  628 lines

  1. /*
  2.  *   stunnel       Universal SSL tunnel
  3.  *   Copyright (c) 1998-2003 Michal Trojnara <Michal.Trojnara@mirt.net>
  4.  *                 All Rights Reserved
  5.  *
  6.  *   Version:      4.04             (stunnel.c)
  7.  *   Date:         2003.01.12
  8.  *
  9.  *   Author:       Michal Trojnara  <Michal.Trojnara@mirt.net>
  10.  *
  11.  *   This program is free software; you can redistribute it and/or modify
  12.  *   it under the terms of the GNU General Public License as published by
  13.  *   the Free Software Foundation; either version 2 of the License, or
  14.  *   (at your option) any later version.
  15.  *
  16.  *   This program is distributed in the hope that it will be useful,
  17.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  *   GNU General Public License for more details.
  20.  *
  21.  *   You should have received a copy of the GNU General Public License
  22.  *   along with this program; if not, write to the Free Software
  23.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  *
  25.  *   In addition, as a special exception, Michal Trojnara gives
  26.  *   permission to link the code of this program with the OpenSSL
  27.  *   library (or with modified versions of OpenSSL that use the same
  28.  *   license as OpenSSL), and distribute linked combinations including
  29.  *   the two.  You must obey the GNU General Public License in all
  30.  *   respects for all of the code used other than OpenSSL.  If you modify
  31.  *   this file, you may extend this exception to your version of the
  32.  *   file, but you are not obligated to do so.  If you do not wish to
  33.  *   do so, delete this exception statement from your version.
  34.  */
  35.  
  36. #include "common.h"
  37. #include "prototypes.h"
  38.  
  39.     /* Prototypes */
  40. static void daemon_loop(void);
  41. static void accept_connection(LOCAL_OPTIONS *);
  42. static void get_limits(void); /* setup global max_clients and max_fds */
  43. #if !defined (USE_WIN32) && !defined (__vms)
  44. static void drop_privileges(void);
  45. static void daemonize(void);
  46. static void create_pid(void);
  47. static void delete_pid(void);
  48. #endif
  49. static void setnonblock(int, unsigned long);
  50.  
  51.     /* Error/exceptions handling functions */
  52. #ifndef USE_WIN32
  53. static void signal_handler(int);
  54. #endif
  55.  
  56. int num_clients=0; /* Current number of clients */
  57.  
  58.     /* Functions */
  59.  
  60. #ifndef USE_WIN32
  61. int main(int argc, char* argv[]) { /* execution begins here 8-) */
  62.  
  63.     main_initialize(argc>1 ? argv[1] : NULL);
  64.  
  65.     signal(SIGPIPE, SIG_IGN); /* avoid 'broken pipe' signal */
  66.     signal(SIGTERM, signal_handler);
  67.     signal(SIGQUIT, signal_handler);
  68.     signal(SIGINT, signal_handler);
  69.     signal(SIGHUP, signal_handler);
  70.     /* signal(SIGSEGV, signal_handler); */
  71.  
  72.     main_execute();
  73.  
  74.     return 0; /* success */
  75. }
  76. #endif
  77.  
  78. void main_initialize(char *arguments) {
  79.     struct stat st; /* buffer for stat */
  80.  
  81.     sthreads_init(); /* initialize critical sections & SSL callbacks */
  82.     parse_config(arguments);
  83.     log_open();
  84.     log(LOG_NOTICE, "%s", stunnel_info());
  85.  
  86.     /* check if certificate exists */
  87.     if(!options.key) /* key file not specified */
  88.         options.key=options.cert;
  89.     if(options.option.cert) {
  90.         if(stat(options.key, &st)) {
  91.             ioerror(options.key);
  92.             exit(1);
  93.         }
  94. #ifndef USE_WIN32
  95.         if(st.st_mode & 7)
  96.             log(LOG_WARNING, "Wrong permissions on %s", options.key);
  97. #endif /* defined USE_WIN32 */
  98.     }
  99. }
  100.  
  101. void main_execute(void) {
  102.     context_init(); /* initialize global SSL context */
  103.     /* check if started from inetd */
  104.     if(local_options.next) { /* there are service sections -> daemon mode */
  105.         daemon_loop();
  106.     } else { /* inetd mode */
  107. #if !defined (USE_WIN32) && !defined (__vms)
  108.         max_fds=16; /* just in case */
  109.         drop_privileges();
  110. #endif
  111.         num_clients=1;
  112.         client(alloc_client_session(&local_options, 0, 1));
  113.     }
  114.     /* close SSL */
  115.     context_free(); /* free global SSL context */
  116.     log_close();
  117. }
  118.  
  119. static void daemon_loop(void) {
  120.     struct sockaddr_in addr;
  121.     fd_set base_set, current_set;
  122.     int n;
  123.     LOCAL_OPTIONS *opt;
  124.  
  125.     get_limits();
  126.     FD_ZERO(&base_set);
  127.     if(!local_options.next) {
  128.         log(LOG_ERR, "No connections defined in config file");
  129.         exit(1);
  130.     }
  131.  
  132.     num_clients=0;
  133.  
  134.     /* bind local ports */
  135.     n=0;
  136.     for(opt=local_options.next; opt; opt=opt->next) {
  137.         if(!opt->option.accept) /* no need to bind this service */
  138.             continue;
  139.         if((opt->fd=socket(AF_INET, SOCK_STREAM, 0))<0) {
  140.             sockerror("local socket");
  141.             exit(1);
  142.         }
  143.         if(alloc_fd(opt->fd))
  144.             exit(1);
  145.         if(set_socket_options(opt->fd, 0)<0)
  146.             exit(1);
  147.         memset(&addr, 0, sizeof(addr));
  148.         addr.sin_family=AF_INET;
  149.         addr.sin_addr.s_addr=*opt->localnames;
  150.         addr.sin_port=opt->localport;
  151.         safe_ntoa(opt->local_address, addr.sin_addr);
  152.         if(bind(opt->fd, (struct sockaddr *)&addr, sizeof(addr))) {
  153.             log(LOG_ERR, "Error binding %s to %s:%d", opt->servname,
  154.                 opt->local_address, ntohs(addr.sin_port));
  155.             sockerror("bind");
  156.             exit(1);
  157.         }
  158.         log(LOG_DEBUG, "%s bound to %s:%d", opt->servname,
  159.             opt->local_address, ntohs(addr.sin_port));
  160.         if(listen(opt->fd, 5)) {
  161.             sockerror("listen");
  162.             exit(1);
  163.         }
  164. #ifdef FD_CLOEXEC
  165.         fcntl(opt->fd, F_SETFD, FD_CLOEXEC); /* close socket in child execvp */
  166. #endif
  167.         FD_SET(opt->fd, &base_set);
  168.         if(opt->fd > n)
  169.             n=opt->fd;
  170.     }
  171.  
  172. #ifndef USE_WIN32
  173.     sselect_init(&base_set, &n);
  174. #endif
  175.  
  176. #if !defined (USE_WIN32) && !defined (__vms)
  177.     if(!(options.option.foreground))
  178.         daemonize();
  179.     drop_privileges();
  180.     create_pid();
  181. #endif /* !defined USE_WIN32 && !defined (__vms) */
  182.  
  183.     /* create exec+connect services */
  184.     for(opt=local_options.next; opt; opt=opt->next) {
  185.         if(opt->option.accept) /* skip ordinary (accepting) services */
  186.             continue;
  187.         enter_critical_section(CRIT_CLIENTS); /* for multi-cpu machines */
  188.         num_clients++;
  189.         leave_critical_section(CRIT_CLIENTS);
  190.         create_client(-1, -1, alloc_client_session(opt, -1, -1), client);
  191.     }
  192.  
  193.     while(1) {
  194.         memcpy(¤t_set, &base_set, sizeof(fd_set));
  195.         if(sselect(n+1, ¤t_set, NULL, NULL, NULL)<0)
  196.             /* non-critical error */
  197.             log_error(LOG_INFO, get_last_socket_error(), "main loop select");
  198.         else 
  199.             for(opt=local_options.next; opt; opt=opt->next)
  200.                 if(FD_ISSET(opt->fd, ¤t_set))
  201.                     accept_connection(opt);
  202.     }
  203.     log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)");
  204. }
  205.  
  206. static void accept_connection(LOCAL_OPTIONS *opt) {
  207.     struct sockaddr_in addr;
  208.     int s, addrlen=sizeof(addr);
  209.  
  210.     do {
  211.         s=accept(opt->fd, (struct sockaddr *)&addr, &addrlen);
  212.     } while(s<0 && get_last_socket_error()==EINTR);
  213.     if(s<0) {
  214.         sockerror("accept");
  215.         return;
  216.     }
  217.     enter_critical_section(CRIT_NTOA); /* inet_ntoa is not mt-safe */
  218.     log(LOG_DEBUG, "%s accepted FD=%d from %s:%d", opt->servname, s,
  219.         inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  220.     leave_critical_section(CRIT_NTOA);
  221.     if(num_clients>=max_clients) {
  222.         log(LOG_WARNING, "Connection rejected: too many clients (>=%d)",
  223.             max_clients);
  224.         closesocket(s);
  225.         return;
  226.     }
  227.     if(alloc_fd(s))
  228.         return;
  229. #ifdef FD_CLOEXEC
  230.     fcntl(s, F_SETFD, FD_CLOEXEC); /* close socket in child execvp */
  231. #endif
  232.     if(create_client(opt->fd, s, alloc_client_session(opt, s, s), client)) {
  233.         log(LOG_ERR, "Connection rejected: create_client failed");
  234.         closesocket(s);
  235.         return;
  236.     }
  237.     enter_critical_section(CRIT_CLIENTS); /* for multi-cpu machines */
  238.     num_clients++;
  239.     leave_critical_section(CRIT_CLIENTS);
  240. }
  241.  
  242. static void get_limits(void) {
  243. #ifdef USE_WIN32
  244.     max_clients=30000;
  245.     log(LOG_NOTICE, "WIN32 platform: %d clients allowed", max_clients);
  246. #else
  247.     int fds_ulimit=-1;
  248.  
  249. #if defined HAVE_SYSCONF
  250.     fds_ulimit=sysconf(_SC_OPEN_MAX);
  251.     if(fds_ulimit<0)
  252.         ioerror("sysconf");
  253. #elif defined HAVE_GETRLIMIT
  254.     struct rlimit rlim;
  255.     if(getrlimit(RLIMIT_NOFILE, &rlim)<0)
  256.         ioerror("getrlimit");
  257.     else
  258.         fds_ulimit=rlim.rlim_cur;
  259.     if(fds_ulimit==RLIM_INFINITY)
  260.         fds_ulimit=-1;
  261. #endif
  262.     if(fds_ulimit>=16 && fds_ulimit<FD_SETSIZE)
  263.         max_fds=fds_ulimit;
  264.     else
  265.         max_fds=FD_SETSIZE;
  266.     max_clients=max_fds>=256 ? max_fds*125/256 : (max_fds-6)/2;
  267.     log(LOG_NOTICE, "FD_SETSIZE=%d, file ulimit=%d%s -> %d clients allowed",
  268.         FD_SETSIZE, fds_ulimit, fds_ulimit<0?" (unlimited)":"", max_clients);
  269. #endif
  270. }
  271.  
  272. #if !defined (USE_WIN32) && !defined (__vms)
  273.     /* chroot and set process user and group(s) id */
  274. static void drop_privileges(void) {
  275.     int uid=0, gid=0;
  276.     struct group *gr;
  277. #ifdef HAVE_SETGROUPS
  278.     gid_t gr_list[1];
  279. #endif
  280.     struct passwd *pw;
  281.  
  282.     /* Get the integer values */
  283.     if(options.setgid_group) {
  284.         gr=getgrnam(options.setgid_group);
  285.         if(gr)
  286.             gid=gr->gr_gid;
  287.         else if(atoi(options.setgid_group)) /* numerical? */
  288.             gid=atoi(options.setgid_group);
  289.         else {
  290.             log(LOG_ERR, "Failed to get GID for group %s",
  291.                 options.setgid_group);
  292.             exit(1);
  293.         }
  294.     }
  295.     if(options.setuid_user) {
  296.         pw=getpwnam(options.setuid_user);
  297.         if(pw)
  298.             uid=pw->pw_uid;
  299.         else if(atoi(options.setuid_user)) /* numerical? */
  300.             uid=atoi(options.setuid_user);
  301.         else {
  302.             log(LOG_ERR, "Failed to get UID for user %s",
  303.                 options.setuid_user);
  304.             exit(1);
  305.         }
  306.     }
  307.  
  308. #ifdef HAVE_CHROOT
  309.     /* chroot */
  310.     if(options.chroot_dir) {
  311.         if(chroot(options.chroot_dir)) {
  312.             sockerror("chroot");
  313.             exit(1);
  314.         }
  315.         if(chdir("/")) {
  316.             sockerror("chdir");
  317.             exit(1);
  318.         }
  319.     }
  320. #endif /* HAVE_CHROOT */
  321.  
  322.     /* Set uid and gid */
  323.     if(gid) {
  324.         if(setgid(gid)) {
  325.             sockerror("setgid");
  326.             exit(1);
  327.         }
  328. #ifdef HAVE_SETGROUPS
  329.         gr_list[0]=gid;
  330.         if(setgroups(1, gr_list)) {
  331.             sockerror("setgroups");
  332.             exit(1);
  333.         }
  334. #endif
  335.     }
  336.     if(uid) {
  337.         if(setuid(uid)) {
  338.             sockerror("setuid");
  339.             exit(1);
  340.         }
  341.     }
  342. }
  343.  
  344. static void daemonize(void) { /* go to background */
  345. #if defined(HAVE_DAEMON) && !defined(__BEOS__)
  346.     if(daemon(0,0)==-1){
  347.         ioerror("daemon");
  348.         exit(1);
  349.     }
  350. #else
  351.     chdir("/");
  352.     switch(fork()) {
  353.     case -1:    /* fork failed */
  354.         ioerror("fork");
  355.         exit(1);
  356.     case 0:     /* child */
  357.         break;
  358.     default:    /* parent */
  359.         exit(0);
  360.     }
  361.     if (setsid() == -1) {
  362.         ioerror("setsid");
  363.         exit(1);
  364.     }
  365.     close(0);
  366.     close(1);
  367.     close(2);
  368. #endif
  369. }
  370.  
  371. static void create_pid(void) {
  372.     int pf;
  373.     char pid[STRLEN];
  374.  
  375.     if(!options.pidfile) {
  376.         log(LOG_DEBUG, "No pid file being created");
  377.         return;
  378.     }
  379.     if(options.pidfile[0]!='/') {
  380.         log(LOG_ERR, "Pid file (%s) must be full path name", options.pidfile);
  381.         /* Why?  Because we don't want to confuse by
  382.            allowing '.', which would be '/' after
  383.            daemonizing) */
  384.         exit(1);
  385.     }
  386.     options.dpid=(unsigned long)getpid();
  387.  
  388.     /* silently remove old pid file */
  389.     unlink(options.pidfile);
  390.     if((pf=open(options.pidfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL,0644))==-1) {
  391.         log(LOG_ERR, "Cannot create pid file %s", options.pidfile);
  392.         ioerror("create");
  393.         exit(1);
  394.     }
  395.     sprintf(pid, "%lu\n", options.dpid);
  396.     write(pf, pid, strlen(pid));
  397.     close(pf);
  398.     log(LOG_DEBUG, "Created pid file %s", options.pidfile);
  399.     atexit(delete_pid);
  400. }
  401.  
  402. static void delete_pid(void) {
  403.     log(LOG_DEBUG, "removing pid file %s", options.pidfile);
  404.     if((unsigned long)getpid()!=options.dpid)
  405.         return; /* current process is not main daemon process */
  406.     if(unlink(options.pidfile)<0)
  407.         ioerror(options.pidfile); /* not critical */
  408. }
  409. #endif /* defined USE_WIN32 */
  410.  
  411. int set_socket_options(int s, int type) {
  412.     SOCK_OPT *ptr;
  413.     extern SOCK_OPT sock_opts[];
  414.     static char *type_str[3]={"accept", "local", "remote"};
  415.     int opt_size;
  416.  
  417.     for(ptr=sock_opts;ptr->opt_str;ptr++) {
  418.         if(!ptr->opt_val[type])
  419.             continue; /* default */
  420.         switch(ptr->opt_type) {
  421.         case TYPE_LINGER:
  422.             opt_size=sizeof(struct linger); break;
  423.         case TYPE_TIMEVAL:
  424.             opt_size=sizeof(struct timeval); break;
  425.         case TYPE_STRING:
  426.             opt_size=strlen(ptr->opt_val[type]->c_val)+1; break;
  427.         default:
  428.             opt_size=sizeof(int); break;
  429.         }
  430.         if(setsockopt(s, ptr->opt_level, ptr->opt_name,
  431.                 (void *)ptr->opt_val[type], opt_size)) {
  432.             sockerror(ptr->opt_str);
  433.             return -1; /* FAILED */
  434.         } else {
  435.             log(LOG_DEBUG, "%s option set on %s socket",
  436.                 ptr->opt_str, type_str[type]);
  437.         }
  438.     }
  439.     return 0; /* OK */
  440. }
  441.  
  442. void ioerror(char *txt) { /* input/output error handler */
  443.     log_error(LOG_ERR, get_last_error(), txt);
  444. }
  445.  
  446. void sockerror(char *txt) { /* socket error handler */
  447.     log_error(LOG_ERR, get_last_socket_error(), txt);
  448. }
  449.  
  450. void log_error(int level, int error, char *txt) { /* generic error logger */
  451.     log(level, "%s: %s (%d)", txt, my_strerror(error), error);
  452. }
  453.  
  454. char *my_strerror(int errnum) {
  455.     switch(errnum) {
  456. #ifdef USE_WIN32
  457.     case 10004:
  458.         return "Interrupted system call (WSAEINTR)";
  459.     case 10009:
  460.         return "Bad file number (WSAEBADF)";
  461.     case 10013:
  462.         return "Permission denied (WSAEACCES)";
  463.     case 10014:
  464.         return "Bad address (WSAEFAULT)";
  465.     case 10022:
  466.         return "Invalid argument (WSAEINVAL)";
  467.     case 10024:
  468.         return "Too many open files (WSAEMFILE)";
  469.     case 10035:
  470.         return "Operation would block (WSAEWOULDBLOCK)";
  471.     case 10036:
  472.         return "Operation now in progress (WSAEINPROGRESS)";
  473.     case 10037:
  474.         return "Operation already in progress (WSAEALREADY)";
  475.     case 10038:
  476.         return "Socket operation on non-socket (WSAENOTSOCK)";
  477.     case 10039:
  478.         return "Destination address required (WSAEDESTADDRREQ)";
  479.     case 10040:
  480.         return "Message too long (WSAEMSGSIZE)";
  481.     case 10041:
  482.         return "Protocol wrong type for socket (WSAEPROTOTYPE)";
  483.     case 10042:
  484.         return "Bad protocol option (WSAENOPROTOOPT)";
  485.     case 10043:
  486.         return "Protocol not supported (WSAEPROTONOSUPPORT)";
  487.     case 10044:
  488.         return "Socket type not supported (WSAESOCKTNOSUPPORT)";
  489.     case 10045:
  490.         return "Operation not supported on socket (WSAEOPNOTSUPP)";
  491.     case 10046:
  492.         return "Protocol family not supported (WSAEPFNOSUPPORT)";
  493.     case 10047:
  494.         return "Address family not supported by protocol family (WSAEAFNOSUPPORT)";
  495.     case 10048:
  496.         return "Address already in use (WSAEADDRINUSE)";
  497.     case 10049:
  498.         return "Can't assign requested address (WSAEADDRNOTAVAIL)";
  499.     case 10050:
  500.         return "Network is down (WSAENETDOWN)";
  501.     case 10051:
  502.         return "Network is unreachable (WSAENETUNREACH)";
  503.     case 10052:
  504.         return "Net dropped connection or reset (WSAENETRESET)";
  505.     case 10053:
  506.         return "Software caused connection abort (WSAECONNABORTED)";
  507.     case 10054:
  508.         return "Connection reset by peer (WSAECONNRESET)";
  509.     case 10055:
  510.         return "No buffer space available (WSAENOBUFS)";
  511.     case 10056:
  512.         return "Socket is already connected (WSAEISCONN)";
  513.     case 10057:
  514.         return "Socket is not connected (WSAENOTCONN)";
  515.     case 10058:
  516.         return "Can't send after socket shutdown (WSAESHUTDOWN)";
  517.     case 10059:
  518.         return "Too many references, can't splice (WSAETOOMANYREFS)";
  519.     case 10060:
  520.         return "Connection timed out (WSAETIMEDOUT)";
  521.     case 10061:
  522.         return "Connection refused (WSAECONNREFUSED)";
  523.     case 10062:
  524.         return "Too many levels of symbolic links (WSAELOOP)";
  525.     case 10063:
  526.         return "File name too long (WSAENAMETOOLONG)";
  527.     case 10064:
  528.         return "Host is down (WSAEHOSTDOWN)";
  529.     case 10065:
  530.         return "No Route to Host (WSAEHOSTUNREACH)";
  531.     case 10066:
  532.         return "Directory not empty (WSAENOTEMPTY)";
  533.     case 10067:
  534.         return "Too many processes (WSAEPROCLIM)";
  535.     case 10068:
  536.         return "Too many users (WSAEUSERS)";
  537.     case 10069:
  538.         return "Disc Quota Exceeded (WSAEDQUOT)";
  539.     case 10070:
  540.         return "Stale NFS file handle (WSAESTALE)";
  541.     case 10091:
  542.         return "Network SubSystem is unavailable (WSASYSNOTREADY)";
  543.     case 10092:
  544.         return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)";
  545.     case 10093:
  546.         return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)";
  547.     case 10071:
  548.         return "Too many levels of remote in path (WSAEREMOTE)";
  549.     case 11001:
  550.         return "Host not found (WSAHOST_NOT_FOUND)";
  551.     case 11002:
  552.         return "Non-Authoritative Host not found (WSATRY_AGAIN)";
  553.     case 11003:
  554.         return "Non-Recoverable errors: FORMERR, REFUSED, NOTIMP (WSANO_RECOVERY)";
  555.     case 11004:
  556.         return "Valid name, no data record of requested type (WSANO_DATA)";
  557. #if 0
  558.     case 11004: /* typically, only WSANO_DATA is reported */
  559.         return "No address, look for MX record (WSANO_ADDRESS)";
  560. #endif
  561. #endif /* defined USE_WIN32 */
  562.     default:
  563.         return strerror(errnum);
  564.     }
  565. }
  566.  
  567. #ifndef USE_WIN32
  568.  
  569. static void signal_handler(int sig) { /* signal handler */
  570.     log(sig==SIGTERM ? LOG_NOTICE : LOG_ERR,
  571.         "Received signal %d; terminating", sig);
  572.     exit(3);
  573. }
  574.  
  575. #endif /* !defined USE_WIN32 */
  576.  
  577. char *stunnel_info(void) {
  578.     static char retval[STRLEN];
  579.  
  580.     safecopy(retval, "stunnel " VERSION " on " HOST);
  581. #ifdef USE_PTHREAD
  582.     safeconcat(retval, " PTHREAD");
  583. #endif
  584. #ifdef USE_WIN32
  585.     safeconcat(retval, " WIN32");
  586. #endif
  587. #ifdef USE_FORK
  588.     safeconcat(retval, " FORK");
  589. #endif
  590. #ifdef USE_LIBWRAP
  591.     safeconcat(retval, "+LIBWRAP");
  592. #endif
  593.     safeconcat(retval, " with ");
  594.     safeconcat(retval, SSLeay_version(SSLEAY_VERSION));
  595.     return retval;
  596. }
  597.  
  598. int alloc_fd(int sock) {
  599. #ifndef USE_WIN32
  600.     if(sock>=max_fds) {
  601.         log(LOG_ERR,
  602.             "File descriptor out of range (%d>=%d)", sock, max_fds);
  603.         closesocket(sock);
  604.         return -1;
  605.     }
  606. #endif
  607.     setnonblock(sock, 1);
  608.     return 0;
  609. }
  610.  
  611. static void setnonblock(int sock, unsigned long l) {
  612.     if(ioctlsocket(sock, FIONBIO, &l)<0)
  613.         sockerror("nonblocking"); /* non-critical */
  614.     else
  615.         log(LOG_DEBUG, "FD %d in %sblocking mode", sock,
  616.             l ? "non-" : "");
  617. }
  618.  
  619. char *safe_ntoa(char *text, struct in_addr in) {
  620.     enter_critical_section(CRIT_NTOA); /* inet_ntoa is not mt-safe */
  621.     strncpy(text, inet_ntoa(in), 15);
  622.     leave_critical_section(CRIT_NTOA);
  623.     text[15]='\0';
  624.     return text;
  625. }
  626.  
  627. /* End of stunnel.c */
  628.